package se.slackers.automatunes.algorithm;

import se.slackers.automatunes.ui.BooleanParameter;
import se.slackers.automatunes.ui.FloatParameter;
import se.slackers.automatunes.ui.ParameterSet;

public class GameOfLifeRule implements AutomataRule {
	public static final String LIFE_LIMIT = "Life limit";
	public static final String DECREMENT = "Decrement";
	private static final String SURVIVE_MIN = "Survive min";
	private static final String SURVIVE_MAX = "Survive max";
	private static final String BIRTH_MIN = "Birth min";
	private static final String BIRTH_MAX = "Birth max";
	private static final String WRAP = "Wrap field";

	private final ParameterSet parameter;

	public GameOfLifeRule() {
		parameter = new ParameterSet();
		parameter.add(new FloatParameter(DECREMENT, 1, 0, 1));
		parameter.add(new FloatParameter(LIFE_LIMIT, 1, 0, 1));
		parameter.add(new FloatParameter(SURVIVE_MIN, 2, 0, 8));
		parameter.add(new FloatParameter(SURVIVE_MAX, 4, 0, 8));
		parameter.add(new FloatParameter(BIRTH_MIN, 3, 0, 8));
		parameter.add(new FloatParameter(BIRTH_MAX, 4, 0, 8));
		parameter.add(new BooleanParameter(WRAP, false).tooltip("Wrap field edges"));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see se.slackers.automatunes.algorithm.AutomataRule#apply(se.slackers.automatunes.algorithm.Field,
	 * se.slackers.automatunes.algorithm.Field)
	 */
	@Override
	public void apply(final Field from, final Field to) {
		final float lifeLimit = parameter.getFloat(LIFE_LIMIT);
		final float decrement = parameter.getFloat(DECREMENT);
		final float surviveMin = parameter.getFloat(SURVIVE_MIN);
		final float surviveMax = parameter.getFloat(SURVIVE_MAX);
		final float birthMin = parameter.getFloat(BIRTH_MIN);
		final float birthMax = parameter.getFloat(BIRTH_MAX);
		from.wrap(parameter.getBoolean(WRAP));

		// Any live cell with fewer than two live neighbours dies, as if caused by under-population.
		// Any live cell with two or three live neighbours lives on to the next generation.
		// Any live cell with more than three live neighbours dies, as if by overcrowding.
		// Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

		int index = 0;
		for (int y = 0; y < from.height(); y++) {
			for (int x = 0; x < from.width(); x++) {
				final float neighbours = from.sumNeigbours(x, y);

				if (from.get(x, y) >= lifeLimit) {
					if (surviveMin <= neighbours && neighbours < surviveMax) {
						to.set(index, Field.LIVE);
					} else {
						to.set(index, Math.max(0, to.get(index) - decrement));
					}
				} else {
					if (birthMin <= neighbours && neighbours < birthMax) {
						to.set(index, Field.LIVE);
					} else {
						to.set(index, Math.max(0, to.get(index) - decrement));
					}
				}
				index++;
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see se.slackers.automatunes.ui.HasParameters#getParameters()
	 */
	@Override
	public ParameterSet parameters() {
		return parameter;
	}
}
